//////////////////////////////////////////////////////////////////////
//
// NO_MemberFunction.h header for the $1 class.
//
//////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////
#ifndef NO_MemberFunction_H
#define NO_MemberFunction_H

//////////////////////////////////////////////////////////////////////////
#include "NO_Includes.h"
#include "NO_Function.h"

//////////////////////////////////////////////////////////////////////////
class NO_Type;
class NO_TypeList;

//////////////////////////////////////////////////////////////////////////
//
//	Part 1
//
//////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////
// NO_MemberFunction
//////////////////////////////////////////////////////////////////////////
class NO_DLL_TAL NO_MemberFunction : public NO_IFunction
{
public:	
	//////////////////////////////////////////////////////////////////////////
	NO_MemberFunction(const NO_Int8*);
	virtual ~NO_MemberFunction();

	//////////////////////////////////////////////////////////////////////////
	virtual void operator() (NO_Object& obj, NO_ObjectList& params, NO_Object& ret)	const = 0; 
	virtual void operator() (NO_Object& obj, NO_ObjectList& params)					const = 0; 
	virtual void operator() (NO_ObjectList& params, NO_Object& ret)	const;
	virtual void operator() (NO_ObjectList& params)					const;
	
	//////////////////////////////////////////////////////////////////////////
	virtual NO_IFuncBind* bind (void) const;
	
	//////////////////////////////////////////////////////////////////////////
	virtual NO_IFuncObject* object (NO_Object& o, NO_ObjectList& p, NO_Object& r)	const = 0;
	virtual NO_IFuncObject* object (NO_Object& o, NO_ObjectList& p)					const = 0;
	virtual NO_IFuncObject* object (NO_ObjectList& p, NO_Object& r)	const;
	virtual NO_IFuncObject* object (NO_ObjectList& p)				const;

	//////////////////////////////////////////////////////////////////////////
	virtual NO_Boolean getIsStatic(void) const;
	virtual NO_Boolean getIsMember(void) const;
};

//////////////////////////////////////////////////////////////////////////
//
//	Part 2
//
//////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////
// NO_MemFunc0 member function with no parameter
//////////////////////////////////////////////////////////////////////////
template<class D, class M,  class OT, class RT = void const *>
class NO_MemFunc0 : public NO_MemberFunction
{
	//////////////////////////////////////////////////////////////////////////
	template<class D, class M, class OT>
		class ObjV : public NO_IFuncObject
	{
	public:	
		//////////////////////////////////////////////////////////////////////////
		ObjV(M m, NO_IFunction const * f, NO_Object& o)
		:NO_IFuncObject(f),o(o)
		{d.bind(noGetDataException<OT>(o),m);}
		
		//////////////////////////////////////////////////////////////////////////
		virtual void operator() (void) const {d();}
		
		//////////////////////////////////////////////////////////////////////////
		NO_ObjectList&		getParameter(NO_ObjectList& l)	const {return l;}
		NO_Object const &	getResult(void)					const {return NO_Object::empty;}
		NO_Object const &	getObject(void)					const {return o;}
		
		//////////////////////////////////////////////////////////////////////////
		D d; 
		NO_Object o;
	};
	
	//////////////////////////////////////////////////////////////////////////
	template<class D, class M, class OT, class RT>
		class ObjR : public NO_IFuncObject
	{
	public:	
		//////////////////////////////////////////////////////////////////////////
		ObjR(M m, NO_IFunction const * f, NO_Object& o, NO_Object& r)
		:NO_IFuncObject(f),r(r)
		,rp(noGetDataException<RT>(r)){}
	
		//////////////////////////////////////////////////////////////////////////
		virtual void operator() (void) const {*rp=d();}
		
		//////////////////////////////////////////////////////////////////////////
		NO_ObjectList&		getParameter(NO_ObjectList& l)	const {return l;}
		NO_Object const &	getResult(void)					const {return r;}
		NO_Object const &	getObject(void)					const {return NO_Object::empty;}
		
		//////////////////////////////////////////////////////////////////////////
		D d; 
		NO_Object r;
		RT* rp;
	};
	
	//////////////////////////////////////////////////////////////////////////
	template<class D, class M, class OT, class RT>
		class Bind : public NO_IFuncBind
	{
	public:	
		//////////////////////////////////////////////////////////////////////////
		Bind(M m, NO_IFunction const * f, OT& ob)		:NO_IFuncBind(f)		{d.bind(&ob,m);}
		Bind(M m, NO_IFunction const * f, NO_Object& o)	:NO_IFuncBind(f),o(o)	{d.bind(noGetDataException<OT>(o),m);}
		
		//////////////////////////////////////////////////////////////////////////
		NO_TypeList&		getParameter(NO_TypeList& l) const {return l;}
		NO_Type const &		getResult(void)				 const {return NO_TypeID<RT>::type();}
		NO_Object const &	getObject(void)				 const {return o;}
		
		//////////////////////////////////////////////////////////////////////////
		virtual void operator() (NO_ObjectList& p, NO_Object& r) const {(*(noGetDataException<RT>(r)))=d();}
		virtual void operator() (NO_ObjectList& p)				 const {d();}
		
		//////////////////////////////////////////////////////////////////////////
		D d; 
		NO_Object o;
	};
	
public:
	//////////////////////////////////////////////////////////////////////////
	typedef ObjV<D,M,OT>	object_v;
	typedef ObjR<D,M,OT,RT>	object_r;		
	typedef Bind<D,M,OT,RT>	bind_fun;
	
	//////////////////////////////////////////////////////////////////////////
	NO_MemFunc0(M m, const NO_Int8* n):NO_MemberFunction(n),m(m){}
	
	//////////////////////////////////////////////////////////////////////////
	virtual NO_IFuncObject* object (NO_Object& o, NO_ObjectList& p, NO_Object& r) const {return new object_r(m,this,o,r);}
	virtual NO_IFuncObject* object (NO_Object& o, NO_ObjectList& p)				  const {return new object_v(m,this,o);}
	
	//////////////////////////////////////////////////////////////////////////
	virtual NO_IFuncBind* bind (NO_Object& o) const {return new bind_fun(m,this,o);}
	virtual NO_IFuncBind* bind (OT& o)		  const {return new bind_fun(m,this,o);}
	
	//////////////////////////////////////////////////////////////////////////
	virtual void operator() (NO_Object& o, NO_ObjectList& p, NO_Object& r) const {object_r(m,this,o,r)();}
	virtual void operator() (NO_Object& o, NO_ObjectList& p)			   const {object_v(m,this,o)();}
	
	//////////////////////////////////////////////////////////////////////////
	virtual NO_Type const &	getObjectType(void)				const {return NO_TypeID<OT>::type();}
	virtual NO_Type const &	getReturnType(void)				const {return ((typeid(RT)==typeid(DV)) ? NO_TypeID<void>::type() : NO_TypeID<RT>::type());}
	virtual NO_TypeList&	getParameter (NO_TypeList& p)	const {return p;}
	
protected:
	//////////////////////////////////////////////////////////////////////////
	M m;
};

//////////////////////////////////////////////////////////////////////////
// NO_MemFunc1 member function with one parameter
//////////////////////////////////////////////////////////////////////////
template<class D, class M,  class P1, class OT, class RT = void const *>
class NO_MemFunc1 : public NO_MemberFunction
{
	//////////////////////////////////////////////////////////////////////////
	template<class D, class M, class P1, class OT, class RT>
	class ObjR : public NO_IFuncObject
	{
	public:	
		//////////////////////////////////////////////////////////////////////////
		ObjR(M m, NO_IFunction const * f, NO_Object& o, NO_Object& p, NO_Object& r)
		:NO_IFuncObject(f),o(o), p1(p), r(r)
		,rp(noGetDataException<RT>(r))
		,p1p(noGetDataException<P1>(p))
		{d.bind(noGetDataException<OT>(o),m);}
		
		//////////////////////////////////////////////////////////////////////////
		virtual void operator() (void) const {*rp=d(*p1p);}
		
		//////////////////////////////////////////////////////////////////////////
		NO_ObjectList&		getParameter(NO_ObjectList& l)	const {return l<<p1;}
		NO_Object const &	getResult(void)					const {return r;}
		NO_Object const &	getObject(void)					const {return o;}
		
		//////////////////////////////////////////////////////////////////////////
		D d; 
		NO_Object o, r, p1;
		RT* rp; P1* p1p;
	};
	
	//////////////////////////////////////////////////////////////////////////
	template<class D, class M, class P1, class OT>
	class ObjV : public NO_IFuncObject
	{
	public:	
		//////////////////////////////////////////////////////////////////////////
		ObjV(M m, NO_IFunction const * f, NO_Object& o, NO_Object& p)
		:NO_IFuncObject(f),o(o), p1(p)
		,p1p(noGetDataException<P1>(p))
		{d.bind(noGetDataException<OT>(o),m);}
		
		//////////////////////////////////////////////////////////////////////////
		virtual void operator() (void) const {d(*p1p);}
		
		//////////////////////////////////////////////////////////////////////////
		NO_ObjectList&		getParameter(NO_ObjectList& l)	const {return l<<p1;}
		NO_Object const &	getResult(void)					const {return NO_Object::empty;}
		NO_Object const &	getObject(void)					const {return o;}
		
		//////////////////////////////////////////////////////////////////////////
		D d; 
		NO_Object o, p1;
		P1* p1p;
	};
	
	//////////////////////////////////////////////////////////////////////////
	template<class D, class M, class P1, class OT, class RT>
	class Bind : public NO_IFuncBind
	{
	public:	
		//////////////////////////////////////////////////////////////////////////
		Bind(M m, NO_IFunction const * f, OT& ob)		:NO_IFuncBind(f)		{d.bind(&ob,m);}
		Bind(M m, NO_IFunction const * f, NO_Object& o)	:NO_IFuncBind(f),o(o)	{d.bind(noGetDataException<OT>(o),m);}
		
		//////////////////////////////////////////////////////////////////////////
		NO_TypeList&		getParameter(NO_TypeList& l)	const {return l<<NO_TypeID<P1>::type();}
		NO_Type const &		getResult(void)					const {return NO_TypeID<RT>::type();}
		NO_Object const &	getObject(void)					const {return o;}
		
		//////////////////////////////////////////////////////////////////////////
		virtual void operator() (NO_ObjectList& p, NO_Object& r) const 
		{
			(*(noGetDataException<RT>(r)))=d(*(noGetDataException<P1>(p.list.at(0))));
		}
		
		//////////////////////////////////////////////////////////////////////////
		virtual void operator() (NO_ObjectList& p) const 
		{
			if (p.list.size()<1){return;}
			d(*(noGetDataException<P1>(p.list.at(0))));
		}
		
		//////////////////////////////////////////////////////////////////////////
		D d; 
		NO_Object o;
	};

public:
	//////////////////////////////////////////////////////////////////////////
	typedef ObjR<D,M,P1,OT,RT>	object_r;		
	typedef ObjV<D,M,P1,OT>		object_v;
	typedef Bind<D,M,P1,OT,RT>	bind_fun;
	
	//////////////////////////////////////////////////////////////////////////
	NO_MemFunc1(M m, const NO_Int8* n):NO_MemberFunction(n),m(m){}
	
	//////////////////////////////////////////////////////////////////////////
	virtual NO_IFuncObject* object (NO_Object& o, NO_ObjectList& p, NO_Object& r) const {return new object_r(m,this,o,p.list.at(0),r);}
	virtual NO_IFuncObject* object (NO_Object& o, NO_ObjectList& p)				  const {return new object_v(m,this,o,p.list.at(0));}
	
	//////////////////////////////////////////////////////////////////////////
	virtual void operator() (NO_Object& o, NO_ObjectList& p, NO_Object& r) const {object_r(m,this,o,p.list.at(0),r)();}
	virtual void operator() (NO_Object& o, NO_ObjectList& p)			   const {object_v(m,this,o,p.list.at(0))();}
	
	//////////////////////////////////////////////////////////////////////////
	virtual NO_IFuncBind* bind (NO_Object& o) const {return new bind_fun(m,this,o);}
	virtual NO_IFuncBind* bind (OT& o)		  const {return new bind_fun(m,this,o);}
	
	//////////////////////////////////////////////////////////////////////////
	virtual const NO_Type&	getObjectType(void)			 const {return NO_TypeID<OT>::type();}
	virtual const NO_Type&	getReturnType(void)			 const {return ((typeid(RT)==typeid(DV)) ? NO_TypeID<void>::type() : NO_TypeID<RT>::type());}
	virtual NO_TypeList&	getParameter (NO_TypeList& p)const {return p<<NO_TypeID<P1>::type();}
	
protected:
	//////////////////////////////////////////////////////////////////////////
	M m;
};
	

//////////////////////////////////////////////////////////////////////////
// NO_MemFunc2 member function with one parameter
//////////////////////////////////////////////////////////////////////////
template<class D, class M,  class P1, class P2, class OT, class RT = void const *>
class NO_MemFunc2 : public NO_MemberFunction
{
	//////////////////////////////////////////////////////////////////////////
	template<class D, class M, class P1, class P2, class OT, class RT>
		class ObjR : public NO_IFuncObject
	{
	public:	
		//////////////////////////////////////////////////////////////////////////
		ObjR(M m, NO_IFunction const* f, NO_Object& o, NO_Object& p1, NO_Object& p2, NO_Object& r)
		:NO_IFuncObject(f),o(o), p1(p1), p2(p2), r(r)
		,rp(noGetDataException<RT>(r))
		,p1p(noGetDataException<P1>(p1))
		,p2p(noGetDataException<P2>(p2))
		{d.bind(noGetDataException<OT>(o),m);}
		
		//////////////////////////////////////////////////////////////////////////
		virtual void operator() (void) const {*rp=d(*p1p,*p2p);}
		
		//////////////////////////////////////////////////////////////////////////
		NO_ObjectList&		getParameter(NO_ObjectList& l)	const {return l<<p1<<p2;}
		NO_Object const &	getResult(void)					const {return r;}
		NO_Object const &	getObject(void)					const {return o;}
		
		//////////////////////////////////////////////////////////////////////////
		D d; 
		NO_Object o, r, p1, p2;
		RT* rp; P1* p1p; P2* p2p;
	};
	
	//////////////////////////////////////////////////////////////////////////
	template<class D, class M, class P1, class P2, class OT>
		class ObjV : public NO_IFuncObject
	{
	public:	
		//////////////////////////////////////////////////////////////////////////
		ObjV(M m, NO_IFunction const * f, NO_Object& o, NO_Object& p1, NO_Object& p2)
		:NO_IFuncObject(f),o(o),p1(p1),p2(p2)
		,p1p(noGetDataException<P1>(p1))
		,p2p(noGetDataException<P2>(p2))
		{d.bind(noGetDataException<OT>(o),m);}
		
		//////////////////////////////////////////////////////////////////////////
		virtual void operator() (void) const {d(*p1p,*p2p);}
		
		//////////////////////////////////////////////////////////////////////////
		NO_ObjectList&		getParameter(NO_ObjectList& l)	const {return l<<p1<<p2;}
		NO_Object const &	getResult(void)					const {return NO_Object::empty;}
		NO_Object const &	getObject(void)					const {return o;}
		
		//////////////////////////////////////////////////////////////////////////
		D d; 
		NO_Object o, p1 ,p2;
		P1* p1p; P2* p2p;
	};
	
	//////////////////////////////////////////////////////////////////////////
	template<class D, class M, class P1, class P2, class OT, class RT>
		class Bind : public NO_IFuncBind
	{
	public:	
		//////////////////////////////////////////////////////////////////////////
		Bind(M m, NO_IFunction const * f, OT& ob)		:NO_IFuncBind(f)		{d.bind(&ob,m);}
		Bind(M m, NO_IFunction const * f, NO_Object& o)	:NO_IFuncBind(f),o(o)	{d.bind(noGetDataException<OT>(o),m);}
		
		//////////////////////////////////////////////////////////////////////////
		NO_TypeList&		getParameter(NO_TypeList& l)const {return l<<NO_TypeID<P1>::type()<<NO_TypeID<P2>::type();}
		NO_Type const &		getResult(void)				const {return NO_TypeID<RT>::type();}
		NO_Object const &	getObject(void)				const {return o;}
		
		//////////////////////////////////////////////////////////////////////////
		virtual void operator() (NO_ObjectList& p, NO_Object& r) const 
		{
			if (p.list.size()<2){return;}
			(*(noGetDataException<RT>(r)))=d(*(noGetDataException<P1>(p.list.at(0)))
				,*(noGetDataException<P2>(p.list.at(1))));
		}
		
		//////////////////////////////////////////////////////////////////////////
		virtual void operator() (NO_ObjectList& p) const 
		{
			if (p.list.size()<2){return;}
			d(*(noGetDataException<P1>(p.list.at(0)))
				,*(noGetDataException<P2>(p.list.at(1))));		
		}
		
		//////////////////////////////////////////////////////////////////////////
		D d; 
		NO_Object o;
	};
	
public:
	
	//////////////////////////////////////////////////////////////////////////
	typedef ObjR<D,M,P1,P2,OT,RT>	object_r;		
	typedef ObjV<D,M,P1,P2,OT>		object_v;		
	typedef Bind<D,M,P1,P2,OT,RT>	bind_fun;		
	
	//////////////////////////////////////////////////////////////////////////
	NO_MemFunc2(M m, const NO_Int8* n):NO_MemberFunction(n),m(m){}
	
	//////////////////////////////////////////////////////////////////////////
	virtual NO_IFuncObject* object (NO_Object& o, NO_ObjectList& p, NO_Object& r) const {return new object_r(m,this,o,p.list.at(0),p.list.at(1),r);}
	virtual NO_IFuncObject* object (NO_Object& o, NO_ObjectList& p)				  const {return new object_v(m,this,o,p.list.at(0),p.list.at(1));}
	
	//////////////////////////////////////////////////////////////////////////
	virtual void operator() (NO_Object& o, NO_ObjectList& p, NO_Object& r) const {object_r(m,this,o,p.list.at(0),p.list.at(1),r)();}
	virtual void operator() (NO_Object& o, NO_ObjectList& p)			   const {object_v(m,this,o,p.list.at(0),p.list.at(1))();}
	
	//////////////////////////////////////////////////////////////////////////
	virtual NO_IFuncBind* bind (NO_Object& o)	const {return new bind_fun(m,this,o);}
	virtual NO_IFuncBind* bind (OT& o)			const {return new bind_fun(m,this,o);}
	virtual NO_IFuncBind* bind (void)			const {return 0;}
	
	//////////////////////////////////////////////////////////////////////////
	virtual const NO_Type&	getObjectType	(void)			const {return NO_TypeID<OT>::type();}
	virtual const NO_Type&	getReturnType	(void)			const {return ((typeid(RT)==typeid(DV)) ? NO_TypeID<void>::type() : NO_TypeID<RT>::type());}
	virtual NO_TypeList&	getParameter	(NO_TypeList& p)const {return p<<NO_TypeID<P1>::type()<<NO_TypeID<P2>::type();}
	
protected:
	//////////////////////////////////////////////////////////////////////////
	M m;
};

#endif 
